//package top.rhynie.web3j;
//
//import com.google.protobuf.Any;
//import com.google.protobuf.ByteString;
//import com.google.protobuf.InvalidProtocolBufferException;
//import com.google.protobuf.Type;
//import com.sun.org.apache.xpath.internal.operations.Bool;
//import org.apache.commons.lang3.StringUtils;
//import org.bouncycastle.util.encoders.Hex;
//import org.springframework.http.HttpEntity;
//import org.springframework.http.HttpHeaders;
//import org.springframework.http.MediaType;
//import org.springframework.http.ResponseEntity;
//import org.tron.common.crypto.ECKey;
//import org.tron.common.crypto.Sha256Sm3Hash;
//import org.tron.common.utils.ByteArray;
//import org.tron.protos.Protocol;
//import org.tron.protos.contract.SmartContractOuterClass;
//import org.tron.walletserver.WalletApi;
//import top.rhynie.web3j.entity.Block;
//import top.rhynie.web3j.enums.TronApiEnum;
//import top.rhynie.web3j.enums.TronNetworkEnum;
//import top.rhynie.web3j.utils.GsonUtil;
//import top.rhynie.web3j.utils.HttpClientUtil;
//
//import java.math.BigInteger;
//import java.util.Arrays;
//import java.util.Collections;
//import java.util.HashMap;
//import java.util.List;
//import java.util.Map;
//import java.util.Objects;
//import java.util.stream.Collectors;
//import java.util.stream.Stream;
//
//
//public class Web3j {
//
//  private String network;
//
//  public String getNetwork() {
//    return network;
//  }
//
//  public void setNetwork(String network) {
//    this.network = network;
//  }
//
//  public Web3j() {
//    this.network = TronNetworkEnum.MAINNET.getUrl();
//  }
//
//  public Web3j(String network) {
//    this.network = network;
//  }
//
//  /**
//   * 根据地址查询账号的信息
//   */
//  public <T> ResponseEntity<T> getAccountInfo(String address, Class<T> responseType) {
//    String url = network + TronApiEnum.ACCOUNT_INFO.getUrl() + address;
//    return HttpClientUtil.get(url, responseType);
//  }
//
//  /**
//   * 查询最新区块信息
//   */
//  public <T> ResponseEntity<T> getNowBlock(Class<T> responseType) {
//    String url = network + TronApiEnum.NOW_BLOCK.getUrl();
//    return HttpClientUtil.get(url, responseType);
//  }
//
//  /**
//   * 根据交易hash查询交易结果
//   * @param value
//   * @return
//   */
//  public boolean getTransactionById(String value) {
//    String url = network + TronApiEnum.TRANSACTION_RESULT.getUrl();
//    HttpHeaders headers = new HttpHeaders();
//    headers.setContentType(MediaType.APPLICATION_JSON);
//    Map<String, String> body = new HashMap<>();
//    body.put("value", value);
//    HttpEntity entity = new HttpEntity(body, headers);
//    ResponseEntity<String> responseEntity = HttpClientUtil.post(url, entity, String.class);
//    Map<String, Object> resultMap = GsonUtil.GsonToMaps(responseEntity.getBody());
//    String ret = resultMap.get("ret").toString();
//    if(ret.contains("SUCCESS")) {
//      return true;
//    } else {
//      return false;
//    }
//  }
//
//  /**
//   * 根据合约地址，查询区块链中的智能合约信息
//   */
//  public <T> ResponseEntity<T> getContract(String address, Class<T> responseType) {
//    String url = network + TronApiEnum.CONTRACT_INFO.getUrl();
//    String hex = ByteArray.toHexString(WalletApi.decodeFromBase58Check(address));
//    HttpHeaders headers = new HttpHeaders();
//    headers.setContentType(MediaType.APPLICATION_JSON);
//    Map<String, String> body = new HashMap<>();
//    body.put("value", hex);
//    HttpEntity entity = new HttpEntity(body, headers);
//    return HttpClientUtil.post(url, entity, responseType);
//  }
//
//  /**
//   * 调用合约的函数，函数类型为view或pure
//   */
//  public String triggerConstantContract(String ownerAddr, String contractAddr, String functionSelector, String parameter, String returnParameter) {
//    String url = network + TronApiEnum.TRIGGER_CONSTANT_CONTRACT.getUrl();
//
//    String functionName = functionSelector.substring(0, functionSelector.indexOf("("));
//
//    List<Type> typeList = Collections.emptyList();
//    if(StringUtils.isNotBlank(parameter)) {
//      List<String> parameterType = Arrays.asList(functionSelector.substring(functionSelector.indexOf("(") + 1,
//          functionSelector.indexOf(")")).split(","));
//      List<String> parameterList = Arrays.asList(parameter.split(","));
//      typeList = Stream.iterate(0, x -> ++x)
//          .limit(parameterList.size())
//          .map(x -> {
//            if ("address".equals(parameterType.get(x))) {
//              return new Address(parameterList.get(x)) {
//              };
//            } else if ("uint".equals(parameterType.get(x))) {
//              return new Uint(new BigInteger(parameterList.get(x))) {
//              };
//            } else if ("uint256".equals(parameterType.get(x))) {
//              return new Uint(new BigInteger(parameterList.get(x))) {
//              };
//            }
//            return null;
//          })
//          .filter(Objects::nonNull)
//          .collect(Collectors.toList());
//    }
//
//    List<String> returnParameterType = Arrays.asList(returnParameter.split(","));
//
//    List<TypeReference<?>> returnTypeList = returnParameterType.stream()
//        .map(p -> {
//          if("bool".equals(p)) {
//            return new TypeReference<Bool>() {};
//          } else if ("address".equals(p)) {
//            return new TypeReference<Address>() {};
//          } else if("address[]".equals(p)) {
//            return new TypeReference<DynamicArray<Address>>() {};
//          } else if("uint".equals(p)) {
//            return new TypeReference<Uint>(){};
//          } else if("uint[]".equals(p)) {
//            return new TypeReference<DynamicArray<Uint>>() {};
//          } else if("string".equals(p)) {
//            return new TypeReference<Utf8String>() {};
//          }
//          return null;
//        })
//        .filter(Objects::nonNull)
//        .collect(Collectors.toList());
//
//    Function function = new Function(functionName, typeList, returnTypeList);
//    String parameterAbi = FunctionEncoder.encode(function).substring(8);
//
//    String ownerHex = ByteArray.toHexString(WalletApi.decodeFromBase58Check(ownerAddr));
//    String contractHex = ByteArray.toHexString(WalletApi.decodeFromBase58Check(contractAddr));
//    Map<String, String> body = new HashMap<>();
//    body.put("owner_address", ownerHex);
//    body.put("contract_address", contractHex);
//    body.put("function_selector", functionSelector);
//    body.put("parameter", parameterAbi);
//    HttpEntity entity = new HttpEntity(body);
//    ResponseEntity<String> response = HttpClientUtil.post(url, entity, String.class);
//
//    Map<String, Object> resultMap = GsonUtil.GsonToMaps(response.getBody());
//
//    String result = resultMap.get("constant_result").toString().replace("[", "").replace("]", "");
//    List<Type> returnParameterList = FunctionReturnDecoder.decode(result, function.getOutputParameters());
//    String returnParameterResult = returnParameterList.stream()
//        .map(t -> {
//          if (Uint.class.isInstance(t)) {
//            return ((Uint) t).getValue().toString();
//          }
//          if (DynamicArray.class.isInstance(t)) {
//            return t.getValue().toString();
//          }
//          return t.getValue().toString();
//        })
//        .filter(Objects::nonNull)
//        .collect(Collectors.joining(";"));
//    return returnParameterResult;
//  }
//
//  /**
//   * 调用合约的函数，函数类型非view或pure
//   */
//  public String triggerSmartContract(String privateKey, String ownerAddr, String contractAddr, String functionSelector, String parameter, long trx, long feeLimit) {
//    byte[] privateBytes = ByteArray.fromHexString(privateKey);
//    ResponseEntity<String> nowBlock = this.getNowBlock(String.class);
//    Map<String, Object> map = GsonUtil.GsonToMaps(nowBlock.getBody());
//    String block_header = map.get("block_header").toString();
//    Block block = GsonUtil.GsonToBean(nowBlock.getBody(), Block.class);
//    Block.BlockHeader blockHeader = GsonUtil.GsonToBean(block_header, Block.BlockHeader.class);
//    blockHeader.convertRawData();
//
//    Long blockTimestamp = blockHeader.getTimestamp();
//    Long blockHeight = blockHeader.getNumber();
//
//    byte[] blockHash = Hex.decode(block.getBlockID());
//    Protocol.Transaction transaction = createSmartContractTransaction(ownerAddr, contractAddr, functionSelector, parameter, trx, feeLimit, blockTimestamp, blockHeight, blockHash);
//    byte[] transactionBytes = transaction.toByteArray();
//    byte[] transaction4 = new byte[0];
//    try {
//      transaction4 = signTransaction2Byte(transactionBytes, privateBytes);
//    } catch (InvalidProtocolBufferException e) {
//      e.printStackTrace();
//    }
//
//    ResponseEntity<String> broadcast = this.broadcastHex(ByteArray.toHexString(transaction4), String.class);
//
//    return broadcast.getBody();
//  }
//
//  public <T> ResponseEntity<T> broadcastHex(String transaction, Class<T> responseType) {
//    String url = network + TronApiEnum.BROADCAST_HEX.getUrl();
//    Map<String, String> body = new HashMap<>();
//    body.put("transaction", transaction);
//    HttpEntity entity = new HttpEntity(body);
//    return HttpClientUtil.post(url, entity, responseType);
//  }
//
//  private Protocol.Transaction createSmartContractTransaction(String ownerAddr, String contractAddr, String functionSelector, String parameter, long trx, long feeLimit, long blockTimestamp, long blockHeight, byte[] blockHash) {
//    Protocol.Transaction.Builder transactionBuilder = Protocol.Transaction.newBuilder();
//
//    /*设置合约内部数据*/
//    Protocol.Transaction.Contract.Builder contractBuilder = Protocol.Transaction.Contract.newBuilder();
//    SmartContractOuterClass.TriggerSmartContract.Builder triggerSmartContractBuilder = SmartContractOuterClass.TriggerSmartContract.newBuilder();
//    ByteString contract = ByteString.copyFrom(WalletApi.decodeFromBase58Check(contractAddr));
//    ByteString bsOwner = ByteString.copyFrom(WalletApi.decodeFromBase58Check(ownerAddr));
//    triggerSmartContractBuilder.setContractAddress(contract);
//    triggerSmartContractBuilder.setOwnerAddress(bsOwner);
//
//    //封装data
//    List<Type> list = Collections.emptyList();
//    if(StringUtils.isNotBlank(parameter)) {
//      List<String> parameterType = Arrays.asList(functionSelector.substring(functionSelector.indexOf("(") + 1,
//          functionSelector.indexOf(")")).split(","));
//      List<String> parameterList = Arrays.asList(parameter.split(","));
//      list = Stream.iterate(0, x -> ++x)
//          .limit(parameterList.size())
//          .map(x -> {
//            if ("address".equals(parameterType.get(x))) {
//              return new Address(parameterList.get(x)) {
//              };
//            } else if ("uint".equals(parameterType.get(x))) {
//              return new Uint(new BigInteger(parameterList.get(x))) {
//              };
//            }
//            return null;
//          })
//          .filter(Objects::nonNull)
//          .collect(Collectors.toList());
//    }
//
//    String functionName = functionSelector.substring(0, functionSelector.indexOf("("));
//    Function function = new Function(functionName, list, Collections.emptyList());
//
//    byte[] input = Hex.decode(FunctionEncoder.encode(function));
//    ByteString data = ByteString.copyFrom(input);
//    triggerSmartContractBuilder.setData(data);
//
//    //调用方法时转trx到合约地址
//    triggerSmartContractBuilder.setCallValue(trx);
//    try {
//      Any any = Any.pack(triggerSmartContractBuilder.build());
//      contractBuilder.setParameter(any);
//    } catch (Exception e) {
//      return null;
//    }
//    /*设置备注，交易过期时间等数据*/
//    contractBuilder.setType(Protocol.Transaction.Contract.ContractType.TriggerSmartContract);
//
//    transactionBuilder.getRawDataBuilder().addContract(contractBuilder).setTimestamp(System.currentTimeMillis())
//        //setFeeLimit 设置交易消耗的能量
//        .setExpiration(blockTimestamp + 10 * 60 * 60 * 1000).setFeeLimit(feeLimit);
//    Protocol.Transaction transaction = transactionBuilder.build();
//    Protocol.Transaction refTransaction = setReference(transaction, blockHeight,blockHash);
//    return refTransaction;
//  }
//
//  /*设置参照块数据*/
//  private Protocol.Transaction setReference(Protocol.Transaction transaction, long blockHeight, byte[] blockHash) {
//    byte[] refBlockNum = ByteArray.fromLong(blockHeight);
//    Protocol.Transaction.raw rawData = transaction.getRawData().toBuilder()
//        .setRefBlockHash(ByteString.copyFrom(ByteArray.subArray(blockHash, 8, 16)))
//        .setRefBlockBytes(ByteString.copyFrom(ByteArray.subArray(refBlockNum, 6, 8))).build();
//    return transaction.toBuilder().setRawData(rawData).build();
//  }
//
//  private byte[] signTransaction2Byte(byte[] transaction, byte[] privateKey)
//      throws InvalidProtocolBufferException {
//    ECKey ecKey = ECKey.fromPrivate(privateKey);
//    Protocol.Transaction transaction1 = Protocol.Transaction.parseFrom(transaction);
//    byte[] rawdata = transaction1.getRawData().toByteArray();
//    byte[] hash = Sha256Sm3Hash.hash(rawdata);
//    byte[] sign = ecKey.sign(hash).toByteArray();
//    return transaction1.toBuilder().addSignature(ByteString.copyFrom(sign)).build().toByteArray();
//  }
//
//  /**
//   * trx转账
//   * @param privateKey
//   * @param from
//   * @param to
//   * @param trx
//   * @param feeLimit
//   * @return
//   */
//  public void transferTrx(String privateKey, String from, String to, long trx, long feeLimit) {
//
//  }
//
//}
